#include "sock_msg.h"
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>

#include <linux/un.h>
#include <sys/socket.h>
#include <fcntl.h>

int cliFd = -1;
int sock_exitFlag = 0;

int initSockClient(void)
{
    int                 fd;
    struct sockaddr_un  serveraddr;

    printf("enter in initSockClient\n");
 
    fd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (fd < 0) {
        fprintf(stderr, "socket: %s\n", strerror(errno));
        return -1;
    }
 
    serveraddr.sun_family = AF_UNIX;
    snprintf(serveraddr.sun_path, sizeof(serveraddr.sun_path), "%s", SOCK_IPC_FILE);
    
    int flags=fcntl(fd,F_GETFL,0);
    fcntl(fd,F_SETFL,flags|O_NONBLOCK);//设置为非阻塞

    int result = connect(fd, (struct sockaddr *)&serveraddr, (socklen_t)sizeof(struct sockaddr_un));
    if (result)
    {
        perror("ops: client\n");
        //exit(1);
        return -1;
    }
    else
    {
        cliFd = fd;
        pthread_t thread_handle;
        char  test_data[32] = "client send data\n";
        clientSendData(test_data,strlen(test_data));
        pthread_create(&thread_handle,NULL,sockRecvFunc,NULL);
    }
    return 0;
}

void * sockRecvFunc(void * paramIn)
{
    fd_set rfds;
    struct timeval tv;
    int retval;
    tv.tv_sec = 2;
    tv.tv_usec = 0;
    char recvBuff[256] = {0};
   while(!sock_exitFlag)
   {
       FD_ZERO(&rfds);
       if(cliFd<0)
       {
           break;
       }
       FD_SET(cliFd, &rfds);

       retval = select(cliFd+1,&rfds,NULL,NULL,&tv);

       if(retval<0)
       {
           perror("select()");
           close(cliFd);
           cliFd = -1;
       }
       else if(retval==0)
       {
           //no data available in 2 second;
       }
       else
       {
           //data received;
           if(FD_ISSET(cliFd, &rfds))
           {
               //printf("received data in sockRecvFunc,");

               int bytesRead = read(cliFd,recvBuff,256);
               
               if(bytesRead>0)
               {
                   printf("data len:%d\n",bytesRead);
//                   ack_msg_node * pstNode = NULL;
//                   init_msg_buf_node(recvBuff,bytesRead,&pstNode);
//
//                   if(pstNode != NULL)
//                   {
//                       append_msg_buff_node(pstNode);
//                   }
               }
               else
               {
                   //printf("data len:%d\n",bytesRead);
                   printf("remote socket closed\n");
                   close(cliFd);
                   cliFd = -1;
               }
           }
       }
   } 

   pthread_detach(pthread_self());

   return (void*)NULL;
}

pthread_mutex_t mutex_sock_send = PTHREAD_MUTEX_INITIALIZER;

/*
 * send data when work as a client
 *
 * */
int clientSendData(char * dataToSend, int dataLen)
{
    int errRet = 0;
    
    int lenMsg = dataLen;

    if(lenMsg>0)
    {
        if(cliFd==-1)
        {
            initSockClient();
        }

        if(cliFd==-1)
        {
            errRet = 2;
            printf("msg connection break down\n");
            return 1;
        }
        pthread_mutex_lock(&mutex_sock_send);
        int bytesWrite = write(cliFd, dataToSend, lenMsg);
        //usleep(500000);
        pthread_mutex_unlock(&mutex_sock_send);
        if(bytesWrite < 0){
            printf("msg send failed,error:%d\n",errno);
        }
        else 
        {
            printf("msg send success,len:%d\n",bytesWrite);
        }
    }
    else
    {
        errRet = 1;
    }    

    return errRet;
}

int cliFd_report = -1;

int serverFd_report = -1;

void * sockServerRecvFunc(void * paramIn)
{
    fd_set rfds;
    struct timeval tv;
    int retval;
    tv.tv_sec = 2;
    tv.tv_usec = 0;
    struct sockaddr_un client_addr;
    socklen_t client_len = 0;
    char recvBuff[256];
    int recvLen = 0;
    int lenLastLeft = 0;
    while(!sock_exitFlag)
    {
       if(cliFd_report<0)
       {
           if(serverFd_report>0)
           {
               cliFd_report = accept(serverFd_report, (struct sockaddr *)&client_addr, &client_len);
               
           }
           else
           {
               initSockServer(0);
           }
       }
       else
       {
            FD_ZERO(&rfds);
            
            FD_SET(cliFd_report, &rfds);
            tv.tv_sec = 2;
            tv.tv_usec = 0;
            retval = select(cliFd_report+1,&rfds,NULL,NULL,&tv);

            if(retval<0)
            {
                perror("select()");
                close(cliFd_report);
                cliFd_report = -1;
            }
            else if(retval==0)
            {
                //no data available in 2 second;
            }
            else
            {
                //data received;
                if(FD_ISSET(cliFd_report, &rfds))
                {
                    recvLen = 0;
                    if(lenLastLeft>0&& lenLastLeft<256)
                    {
                        recvLen = read(cliFd_report,recvBuff+lenLastLeft,256);
                    }
                    else
                    {
                        recvLen = read(cliFd_report,recvBuff,256);
                    }
                    printf("received data in sockRecvFunc,");
                    

                    printf("recvLen:%d\n",recvLen);

                    if(recvLen>0)
                    {
                        lenLastLeft = 0;
                        //procReportMsg(recvLen,recvBuff,&lenLastLeft);                  
                    }
                    else
                    {
                        //the romote sock closed.
                        close(cliFd_report);
                        cliFd_report = -1;
                    }
                    
                }
            }
       }
       usleep(100);       
    } 

   pthread_detach(pthread_self());

   return (void*)NULL;
}

int initSockServer(int needCreateThread)
{
    socklen_t client_len = 0;
 
    struct sockaddr_un server_addr;
    struct sockaddr_un client_addr;
 
    // 创建流套接字
    serverFd_report = socket(AF_UNIX, SOCK_STREAM, 0);

    unlink(SOCK_IPC_FILE);
 
    // 设置服务器接收的连接地址和监听的端口
    server_addr.sun_family = AF_UNIX;                   // 指定网络套接字
    snprintf(server_addr.sun_path,sizeof(server_addr.sun_path),"%s",SOCK_IPC_FILE);
 
    // 绑定（命名）套接字
    bind(serverFd_report, (struct sockaddr *)&server_addr, sizeof(sockaddr_un));
 
    // 创建套接字队列，监听套接字
    listen(serverFd_report, 5);
    
    if(needCreateThread)
    {
        pthread_t thread_handle;
        pthread_create(&thread_handle,NULL,sockServerRecvFunc,NULL);
    }   
 
    // 忽略子进程停止或退出信号
    //signal(SIGCHLD, SIG_IGN);
    return 0;
}
